import { Button, Form, Input, Table, Tag } from "antd";
import type { ColumnsType } from "antd/es/table";
import type { TableRowSelection } from "antd/es/table/interface";
import * as LucideIcon from "lucide-react";
import { SaveIcon, SquarePenIcon, XIcon } from "lucide-react";
import { useEffect, useState } from "react";
import {
  apiModifyRoleWithPermissions,
  apiPermissionTree,
  apiRolePermissions,
} from "~/api";
import type { IPermission } from "~/api/login/type";
import Title from "~/components/ui/title";
import { useTableHeight } from "~/hooks/useTableHeight";
import type { IRole } from "~/types/manage/system/role";

import {
  buildUnionFind,
  collectKeys,
  findAllChildKeys,
  findAllParentKeys,
} from "~/utils/ui.util";

interface Props {
  roleInfo: Partial<IRole>;
  onOk: () => void;
}

export default function Role(props: Props) {
  const tableHeight = useTableHeight(400);
  const [isEdit, setIsEdit] = useState(false);
  const [form] = Form.useForm<IRole>();
  const [roleInfo, setRoleInfo] = useState<Partial<IRole> | null>(null);
  const [loading, setLoading] = useState(false);
  const [saveLoading, setSaveLoading] = useState(false);
  const [dataList, setDataList] = useState<IPermission[]>([]);
  const [expandedRowKeys, setExpandedRowKeys] = useState<(string | number)[]>(
    [],
  );
  const [selectedRowKeys, setSelectedRowKeys] = useState<number[]>([]);

  const _handler = {
    save: async () => {
      if (!roleInfo) {
        return;
      }
      setSaveLoading(true);
      await form.validateFields();
      const fields = form.getFieldsValue(true);
      const resp = await apiModifyRoleWithPermissions({
        role: fields,
        permissionIds: selectedRowKeys,
      });
      setRoleInfo(resp);

      setIsEdit(false);
      setSaveLoading(false);
      _fetch.rolePermissionInfo(resp?.id);
      props.onOk?.();
    },

    cancel: () => {
      setIsEdit(false);
    },
  };

  const _ui: {
    tableColumns: ColumnsType<IPermission>;
    rowSelection: TableRowSelection<IPermission> | undefined;
  } = {
    tableColumns: [
      {
        title: "权限名",
        dataIndex: "name",
        key: "name",
        fixed: "left",
        width: 200,
        render: (value: string, record: IPermission) => {
          const menu = {
            icon: LucideIcon[record.icon as keyof typeof LucideIcon],
          } as any;
          return (
            <div className="flex items-center gap-2">
              {menu.icon && <menu.icon size={18} />}
              {value}
            </div>
          );
        },
      },
      {
        title: <LucideIcon.EyeIcon size={18} />,
        dataIndex: "show",
        key: "show",
        width: 60,
        render: (value) => {
          return !value && <LucideIcon.EyeOffIcon size={18} />;
        },
      },
      {
        title: "权限KEY",
        dataIndex: "key",
        key: "key",
        width: 200,
      },
      {
        title: "权限类型",
        dataIndex: "type",
        key: "type",
        width: 100,
        render: (value) => {
          switch (value) {
            case 1:
              return <Tag color="#2db7f5">页面</Tag>;
            case 2:
              return <Tag color="#87d068">功能</Tag>;
            default:
              break;
          }
        },
      },
      {
        title: "路径",
        dataIndex: "path",
        key: "path",
        width: 120,
      },
      {
        title: "备注",
        dataIndex: "remark",
        key: "remark",
        width: 220,
      },
    ],
    rowSelection: {
      selectedRowKeys,
      getCheckboxProps: () => {
        return {
          disabled: !isEdit,
        };
      },
      onChange(selectedRowKeys, _, info) {
        if (info.type === "all") {
          setSelectedRowKeys(selectedRowKeys as number[]);
        }
      },
      onSelect(record, selected) {
        // 1. 找到当前节点的所有子节点
        const childKeys = findAllChildKeys(dataList, record.id);
        const parentKeys = findAllParentKeys(dataList, record.id);
        // 2. 找到当前节点的所有父节点，递归找到 0
        let temp: number[] = [];
        // 选中的情况下
        if (selected) {
          temp = [
            ...new Set<number>([
              ...selectedRowKeys,
              ...childKeys,
              ...parentKeys,
              record.id,
            ]),
          ];
          setSelectedRowKeys(temp);
          return;
        }
        // 取消选中的情况下
        // 找到需要移除的元素
        const needRemove = [record.id, ...childKeys];
        // 递归判断父级是否需要移除
        const removeUnselectedParents = (parentId: number) => {
          const siblings = findAllChildKeys(dataList, parentId);
          const hasSelectedSibling = selectedRowKeys.some(
            (key) =>
              siblings.includes(key as number) &&
              !needRemove.includes(key as number),
          );
          if (!hasSelectedSibling) {
            needRemove.push(parentId);
            const grandParentId = parentMap.get(parentId);
            if (grandParentId) {
              removeUnselectedParents(grandParentId);
            }
          }
        };
        // 初始化父节点映射
        const parentMap = buildUnionFind(dataList);
        // 从当前节点的父节点开始检查，功能的话，不需要移除父级
        if (record.parentId && record.type !== 2) {
          removeUnselectedParents(record.parentId);
        }
        // 递归判断父级是否需要移除，如果父级下所有子级没有选中的则移除当前父级
        // 去除重合部分 childKeys，
        temp = [
          ...selectedRowKeys.filter((item) => !needRemove.includes(item)),
        ];
        setSelectedRowKeys(temp);
      },
    },
  };

  const _fetch = {
    init: async () => {
      setLoading(true);
      const resp = await apiPermissionTree();
      setDataList(resp);
      setExpandedRowKeys(collectKeys(resp, "id"));
      setLoading(false);
    },
    rolePermissionInfo: async (roleId: number) => {
      const resp = await apiRolePermissions(roleId);
      setSelectedRowKeys(resp.map((item) => item.id));
    },
  };

  useEffect(() => {
    _fetch.init();
  }, []);

  useEffect(() => {
    if (!props.roleInfo) {
      return;
    }
    form.resetFields();
    setRoleInfo(props.roleInfo);
    form.setFieldsValue(props.roleInfo);
    setSelectedRowKeys([]);
    if (!props.roleInfo.id) {
      return;
    }
    _fetch.rolePermissionInfo(props.roleInfo.id);
  }, [props.roleInfo]);

  return (
    <>
      <Title
        title="基本信息"
        buttonGroups={
          isEdit
            ? [
                <Button
                  variant="link"
                  color="default"
                  onClick={() => {
                    _handler.cancel();
                  }}
                >
                  <XIcon size={18} />
                  取消
                </Button>,
                <Button
                  type="link"
                  onClick={() => {
                    _handler.save();
                  }}
                >
                  <SaveIcon size={18} />
                  保存
                </Button>,
              ]
            : [
                <Button
                  type="link"
                  onClick={() => {
                    setIsEdit(true);
                  }}
                >
                  <SquarePenIcon size={18} />
                  编辑
                </Button>,
              ]
        }
      />
      <div className="w-1/2">
        <Form form={form}>
          <Form.Item
            label="角色名称"
            name={"name"}
            rules={[{ required: true, message: "角色名称必填" }]}
          >
            {isEdit ? <Input /> : roleInfo?.name}
          </Form.Item>
          <Form.Item label="描述" name={"desc"}>
            {isEdit ? <Input /> : roleInfo?.desc}
          </Form.Item>
        </Form>
      </div>
      <Title title="权限信息" />
      <div className="rp-[.ant-tree-treenode]:p-2 h-full w-full overflow-auto">
        <Table
          loading={loading}
          scroll={{
            y: tableHeight,
            x: "max-content",
          }}
          rowKey={(item) => item.id}
          columns={_ui.tableColumns}
          dataSource={dataList}
          pagination={false}
          expandable={{
            onExpand(expanded, record) {
              if (expanded) {
                setExpandedRowKeys((pre) => {
                  return [...pre, record.key];
                });
              } else {
                setExpandedRowKeys((pre) => {
                  return pre.filter((item) => item !== record.key);
                });
              }
            },
            expandedRowKeys,
          }}
          rowSelection={_ui.rowSelection}
        />
      </div>
    </>
  );
}
